/***************************************************************************************
* Copyright (c) 2014-2024 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include "sdb.h"

#define NR_WP 32

typedef struct watchpoint {
  int NO;
  struct watchpoint *next;
  char expr[32];
  word_t old_val;
  /* TODO: Add more members if necessary */

} WP;

static WP wp_pool[NR_WP] = {};
static WP *head = NULL, *free_ = NULL;

void init_wp_pool() {
  int i;
  for (i = 0; i < NR_WP; i ++) {
    wp_pool[i].NO = i;
    wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]);
  }

  head = NULL;
  free_ = wp_pool;
}

/* TODO: Implement the functionality of watchpoint */
WP* new_wp() {
  WP * wp= free_;
  free_ = free_->next;
  wp->expr[0] = '\0';
  wp->old_val = 0u;
  wp->next = head;
  head = wp;
  return wp;
}
void free_wp(WP *wp) {
  if(wp == head) {
    head = head ->next;
  }else {
    WP* prev = head;
    while(prev != NULL && prev->next != wp) {
      prev = prev->next;
    }
    prev->next = prev->next->next;
  }
  wp->next = free_;
  free_ = wp;
}

void wp_set(char *e) {
  #define ANSI_COLOR_RED     "\x1b[31m"
  #define ANSI_COLOR_GREEN   "\x1b[32m"
  #define ANSI_COLOR_YELLOW  "\x1b[33m"
  #define ANSI_COLOR_BLUE    "\x1b[34m"
  #define ANSI_COLOR_CYAN    "\x1b[36m"
  #define ANSI_COLOR_RESET   "\x1b[0m"
  bool is_success =true;
  word_t val = expr(e, &is_success);
  if(!is_success) {
    Log("fail to set watchpoint: bad expr");
    return;
  }
  WP* wp = new_wp();
  if(wp==NULL) {
    Log("fail to set watchpoint: no free");
    return;
  }
  wp->old_val = val;
  strcpy(wp->expr, e);
  printf(ANSI_COLOR_BLUE "%-5d " ANSI_COLOR_YELLOW "%-32s " ANSI_COLOR_GREEN "0x%08x \n\n\n\n" ANSI_COLOR_RESET,
        wp->NO, wp->expr, wp->old_val);
  return;
}
void wp_remove(int no) {
  WP *i = head;
  while (i != NULL && i->NO != no)
  {
    i = i->next;
  }
  if(i == NULL) {
    Log("have no this number");
    return;
  }
  free_wp(i);
}

void wp_print() {
  if (head == NULL) {
    printf("No watchpoints set.\n");
    return;
  }

  printf(ANSI_COLOR_CYAN "%-5s %-32s %s\n" ANSI_COLOR_RESET, "NO", "EXPR", "VALUE");
  
  WP *i = head;
  while(i != NULL) {
    printf(ANSI_COLOR_BLUE "%-5d " ANSI_COLOR_YELLOW "%-32s " ANSI_COLOR_GREEN "0x%08x (%u)\n" ANSI_COLOR_RESET,
        i->NO, i->expr, i->old_val, i->old_val);
    i = i->next;
  }
  printf("\n\n\n\n");
}
void wp_check() {
  WP* i = head;
  bool is_success = true;
  printf(ANSI_COLOR_CYAN "   %-5s %-32s %s\n" ANSI_COLOR_RESET, "NO", "EXPR", "VALUE");
  while (i != NULL) {
    word_t val = expr(i->expr, &is_success);
    if (is_success && val != i->old_val) {
      printf(ANSI_COLOR_BLUE "   %-5d " ANSI_COLOR_YELLOW "%-32s " ANSI_COLOR_GREEN "0x%08x (old:0x%08x)\n" ANSI_COLOR_RESET,
        i->NO, i->expr, val, i->old_val);
      i->old_val = val;
    }
    i = i->next;
  }
  printf("\n");
}
